package drds.plus.sql_process.abstract_syntax_tree.configuration;

import drds.plus.util.GeneralUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * <pre>
 *    <table columnName="t1">
 * 		<columns>
 * 			<column columnName="id" type="long" />
 * 			<column columnName="columnName" type="string" />
 * 			<column columnName="school" type="string" />
 * 		</columns>
 * 		<primaryKey>id</primaryKey>
 * 		<secondaryIndexes>
 * 			<indexMeta columnName="second_idx" type="btree">
 * 				<keys>columnName</keys>
 * 				<values>id</values>
 * 			</indexMeta>
 * 		</secondaryIndexes>
 * 	</table>
 * </pre>
 */

/**
 * 每一个索引（或者叫KV更直白点）的描述
 */
public class IndexMapping implements Cloneable {
    /**
     * 表名+列名
     */
    private final String indexName;
    /**
     * 列名字:业务意义上这部分是非主键索引
     */
    private final List<ColumnMetaData> keyColumnMetaDataList;

    /**
     * 值名字:业务意义上这部分是主键
     */
    private final List<ColumnMetaData> valueColumnMetaDataList;

    /**
     * 当前index的类型 @IndexType
     */
    private final IndexType indexType;

    /**
     * 是否强同步,目前只支持主key
     */
    private final boolean isStronglyConsistent;
    private final boolean isPrimaryKeyIndex;

    // ================== 冗余字段 ==============

    /**
     * 表名+index名的方式进行命名的。 在查询时，会先根据.之前的，拿到表名，然后找到对应的schema。 然后再根据.之后的，找到对应的schema
     */
    private final String tableName;
    /**
     * 保存了所有列，方便查找
     */
    private Map<String, ColumnMetaData> columnNameToColumnMetaDataMap = new HashMap();

    public IndexMapping(String tableName, List<ColumnMetaData> keyColumnMetaDataList, List<ColumnMetaData> valueColumnMetaDataList, IndexType indexType, boolean isStronglyConsistent, boolean isPrimaryKeyIndex) {
        this.tableName = tableName;
        this.keyColumnMetaDataList = unique(keyColumnMetaDataList);
        this.valueColumnMetaDataList = unique(valueColumnMetaDataList);
        this.indexType = indexType;

        this.isPrimaryKeyIndex = isPrimaryKeyIndex;
        this.isStronglyConsistent = isStronglyConsistent;
        this.indexName = buildName(tableName, keyColumnMetaDataList);
        this.columnNameToColumnMetaDataMap = buildColumnNameToColumnMetaDataMap();

    }

    private Map<String, ColumnMetaData> buildColumnNameToColumnMetaDataMap() {
        Map<String, ColumnMetaData> columnNameToColumnMetaDataMap = new HashMap();
        if (valueColumnMetaDataList != null) {
            for (ColumnMetaData columnMetaData : valueColumnMetaDataList) {
                columnNameToColumnMetaDataMap.put(columnMetaData.getColumnName(), columnMetaData);
            }
        }

        if (keyColumnMetaDataList != null) {
            for (ColumnMetaData columnMetaData : keyColumnMetaDataList) {
                columnNameToColumnMetaDataMap.put(columnMetaData.getColumnName(), columnMetaData);
            }
        }

        return columnNameToColumnMetaDataMap;
    }

    private String buildName(String tableName, List<ColumnMetaData> columnMetaDataList) {
        StringBuilder sb = new StringBuilder();
        sb.append(tableName).append(".");
        for (ColumnMetaData columnMetaData : columnMetaDataList) {
            sb.append("_" + columnMetaData.getColumnName());
        }
        return sb.toString();
    }

    public ColumnMetaData getColumnMetaData(String name) {
        return this.columnNameToColumnMetaDataMap.get(name);
    }

    public String getIndexName() {
        if (isPrimaryKeyIndex) {
            return tableName; // 如果是主键索引，直接返回逻辑表名
        } else {
            return indexName; // 否则返回索引名，逻辑表名+字段
        }
    }

    public List<ColumnMetaData> getKeyColumnMetaDataList() {
        return keyColumnMetaDataList;
    }

    public List<ColumnMetaData> getValueColumnMetaDataList() {
        return valueColumnMetaDataList;
    }

    public IndexType getIndexType() {
        return indexType;
    }

    public boolean isStronglyConsistent() {
        return isStronglyConsistent;
    }

    public boolean isPrimaryKeyIndex() {
        return isPrimaryKeyIndex;
    }

    public String getTableName() {
        return tableName;
    }

    public String getNameWithOutDot() {
        return indexName.replace(".", "$");
    }

    public String toString() {
        return toStringWithInden(0);
    }

    /**
     * 根据列名获取对应的index columnName column
     */
    public ColumnMetaData getKeyColumnMetaData(String name) {
        for (ColumnMetaData columnMetaData : keyColumnMetaDataList) {
            if (columnMetaData.getColumnName().equals(name)) {
                return columnMetaData;
            }
        }

        return null;
    }

    /**
     * 根据列名获取对应的index value column
     */
    public ColumnMetaData getValueColumnMetaData(String name) {
        for (ColumnMetaData columnMetaData : valueColumnMetaDataList) {
            if (columnMetaData.getColumnName().equals(name)) {
                return columnMetaData;
            }
        }

        return null;
    }

    private List<ColumnMetaData> unique(List<ColumnMetaData> columnMetaDataList) {
        if (columnMetaDataList == null) {
            return null;
        }

        List<ColumnMetaData> list = new ArrayList<ColumnMetaData>(columnMetaDataList.size());
        for (ColumnMetaData columnMetaData : columnMetaDataList) {
            if (!list.contains(columnMetaData)) {
                list.add(columnMetaData);
            }
        }

        return list;
    }

    public String toStringWithInden(int inden) {
        StringBuilder sb = new StringBuilder();
        String tabTittle = GeneralUtil.getTab(inden);
        sb.append(tabTittle).append("[");
        sb.append("indexMeta indexName : ").append(indexName).append("\n");
        buildMetas(inden, sb, keyColumnMetaDataList, "keyColumn :");
        buildMetas(inden, sb, valueColumnMetaDataList, "valueColumn :");
        sb.append(tabTittle).append("]");
        return sb.toString();
    }

    private void buildMetas(int inden, StringBuilder sb, List<ColumnMetaData> metas, String keyName) {
        if (metas != null) {
            String tabContent = GeneralUtil.getTab(inden + 1);
            sb.append(tabContent).append(keyName).append("\n");
            String content = GeneralUtil.getTab(inden + 2);
            sb.append(content);
            for (ColumnMetaData meta : metas) {
                sb.append(meta.toStringWithInden(0));
                sb.append(" ");
            }

            sb.append("\n");
        }
    }

}
